﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.Reflection;

using NLite.Reflection;
using System.Diagnostics;
using System.ComponentModel;
using NLite.Internal;

namespace NLite.Validation.DataAnnotations
{
    class EntityValidator<TEntity>:IValidator<TEntity>
    {
        public IErrorState Validate(TEntity instance)
        {
            const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public;

            var propFailures =
                   from prop in instance.GetType().GetProperties(flags).Where(p=>p.CanRead)
                   from attribute in prop.GetAttributes<ValidationAttribute>(true)
                   where !attribute.IsValid(prop.GetValue(instance, null))
                   select new ErrorItem { Key = prop.Name, Message = FormatErrorMessage(prop, attribute) };
          
            var fieldFailures =
                   from prop in instance.GetType().GetFields(flags)
                   from attribute in prop.GetAttributes<ValidationAttribute>(true)
                   where !attribute.IsValid(prop.GetValue(instance))
                   select new ErrorItem { Key = prop.Name, Message = FormatErrorMessage(prop, attribute) };


           return new ErrorState(propFailures.Union(fieldFailures).Cast<IErrorItem>());
        }

        public IErrorState Validate(IDictionary<string, string> dic)
        {
            dic = dic ?? new Dictionary<string, string>();

            var modelType = typeof(TEntity);
            const BindingFlags flags = BindingFlags.Instance | BindingFlags.Public;

            var propFailures = (
                       from prop in modelType.GetProperties(flags).Where(p => p.CanRead)
                       from attribute in prop.GetAttributes<ValidationAttribute>(true)
                       where dic.ContainsKey(prop.Name) && !attribute.IsValid(dic[prop.Name])
                       select new ErrorItem { Key = prop.Name, Message = FormatErrorMessage(prop, attribute) });

            var fieldFailures = (
                   from prop in modelType.GetFields(flags)
                   from attribute in prop.GetAttributes<ValidationAttribute>(true)
                   where dic.ContainsKey(prop.Name) && !attribute.IsValid(dic[prop.Name])
                   select new ErrorItem { Key = prop.Name, Message = FormatErrorMessage(prop, attribute) });

            return new ErrorState(propFailures.Union(fieldFailures).Cast<IErrorItem>());
        }

        private static string FormatErrorMessage(MemberInfo prop, ValidationAttribute attribute)
        {
            var displayNameAttr = prop.GetAttribute<DisplayNameAttribute>(false);
            var displayName = displayNameAttr != null ? displayNameAttr.DisplayName : prop.Name;
            return attribute.FormatErrorMessage(displayName);
        }
    }

   

   

   
    
}
